package unimelb.discussiontracker.twitter.web.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import unimelb.discussiontracker.twitter.common.QueryControl;
import unimelb.discussiontracker.twitter.service.SearchService;
import unimelb.discussiontracker.twitter.web.model.AjaxRequestResult;
import unimelb.discussiontracker.twitter.web.model.HashTagItem;
import unimelb.discussiontracker.twitter.web.model.IntervalItem;
import unimelb.discussiontracker.twitter.web.model.PaginatedSearchResult;
import unimelb.discussiontracker.twitter.web.model.SearchResultAggregate;
import unimelb.discussiontracker.twitter.web.model.TweetItem;
import unimelb.discussiontracker.twitter.web.model.UserItem;

@Controller
public class SearchController {

    private static final String ENTITY_ALL = "all";

    private static final String ENTITY_TWEET = "tweets";

    private static final String ENTITY_USER = "users";

    private static final String ENTITY_TAG = "tags";

    private static final String DEFAULT_SORT_BY = "strength";

    private static final String DEFAULT_ORDER = "desc";

    private static final String DEFAULT_PAGE_SIZE = "20";

    private static final String DEFAULT_PAGE_NUMBER = "1";

    @Autowired
    private SearchService searchService;

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String showHomePage() {
        return "redirect:/search";
    }
    
    @RequestMapping(value = "/search", method = RequestMethod.GET)
    public String showSearchPage(ModelMap model) {
        model.put("topicList", searchService.searchAllTopics());
        return "searchPage";
    }

    @RequestMapping(value = "/getIntervalList", method = RequestMethod.GET)
    @ResponseBody
    public AjaxRequestResult<List<IntervalItem>> ajaxRetrieveIntervalListForTopic(@RequestParam("topicId") long topicId) {
        return new AjaxRequestResult<List<IntervalItem>>(searchService.searchIntervalsByTopicId(topicId));
    }

    @RequestMapping(value = "/doSearch", method = RequestMethod.POST, produces = "text/html")
    public String searchForEntity(@RequestParam("topicId") long topicId, @RequestParam("intervalId") long intervalId, ModelMap model) {
        final AjaxRequestResult<SearchResultAggregate> searchResult = ajaxSearchForEntity(topicId, intervalId, ENTITY_ALL, DEFAULT_SORT_BY, DEFAULT_ORDER, Integer
                .valueOf(DEFAULT_PAGE_SIZE), Integer.valueOf(DEFAULT_PAGE_NUMBER));
        model.put("interval", searchResult.getResult().getInterval());
        model.put("topTweets", searchResult.getResult().getTweets());
        model.put("topUsers", searchResult.getResult().getUsers());
        model.put("topTags", searchResult.getResult().getTags());
        return "searchResult";
    }

    @RequestMapping(value = "/doSearch", method = RequestMethod.POST, produces = "application/json")
    @ResponseBody
    public AjaxRequestResult<SearchResultAggregate> ajaxSearchForEntity(@RequestParam("topicId") long topicId, @RequestParam("intervalId") long intervalId,
            @RequestParam(value = "entityType", defaultValue = ENTITY_ALL) String entityType,
            @RequestParam(value = "sortBy", defaultValue = DEFAULT_SORT_BY) String sortBy,
            @RequestParam(value = "sortOrder", defaultValue = DEFAULT_ORDER) String sortOrder,
            @RequestParam(value = "pageSize", defaultValue = DEFAULT_PAGE_SIZE) int pageSize,
            @RequestParam(value = "pageNumber", defaultValue = DEFAULT_PAGE_NUMBER) int pageNumber) {
        final QueryControl queryControl = new QueryControl(sortBy, sortOrder, pageSize, pageNumber);

        final IntervalItem interval = searchService.searchTopicIntervalAssocByTopicIdAndIntervalid(topicId, intervalId);

        PaginatedSearchResult<TweetItem> topTweets = null;
        PaginatedSearchResult<UserItem> topUsers = null;
        PaginatedSearchResult<HashTagItem> topTags = null;

        if (ENTITY_TWEET.equalsIgnoreCase(entityType)) {
            topTweets = searchService.searchKeywordBasedTweetRankings(topicId, intervalId, queryControl);
        } else if (ENTITY_USER.equalsIgnoreCase(entityType)) {
            topUsers = searchService.searchKeywordBasedUserRankings(topicId, intervalId, queryControl);
        } else if (ENTITY_TAG.equalsIgnoreCase(entityType)) {
            topTags = searchService.searchKeywordBasedTagRankings(topicId, intervalId, queryControl);
        } else {
            topTweets = searchService.searchKeywordBasedTweetRankings(topicId, intervalId, queryControl);
            topUsers = searchService.searchKeywordBasedUserRankings(topicId, intervalId, queryControl);
            topTags = searchService.searchKeywordBasedTagRankings(topicId, intervalId, queryControl);
        }

        return new AjaxRequestResult<SearchResultAggregate>(new SearchResultAggregate(interval, topTweets, topUsers, topTags));
    }

    @RequestMapping(value = "/doSearchRelatedEntities", method = RequestMethod.POST, produces = "application/json")
    @ResponseBody
    public AjaxRequestResult<SearchResultAggregate> ajaxSearchAllRelatedEntity(@RequestParam("topicId") long topicId,
            @RequestParam("intervalId") long intervalId, @RequestParam("entityId") long entityId, @RequestParam("entityType") String entityType) {
        return ajaxSearchRelatedEntity(topicId, intervalId, entityId, entityType, ENTITY_ALL, DEFAULT_SORT_BY, DEFAULT_ORDER, Integer.valueOf(DEFAULT_PAGE_SIZE), Integer
                .valueOf(DEFAULT_PAGE_NUMBER));
    }

    @RequestMapping(value = "/doSearchRelatedEntity", method = RequestMethod.POST, produces = "application/json")
    @ResponseBody
    public AjaxRequestResult<SearchResultAggregate> ajaxSearchRelatedEntity(@RequestParam("topicId") long topicId, @RequestParam("intervalId") long intervalId,
            @RequestParam("entityId") long entityId, @RequestParam("entityType") String entityType,
            @RequestParam("relatedEntityType") String relatedEntityType, @RequestParam(value = "sortBy", defaultValue = DEFAULT_SORT_BY) String sortBy,
            @RequestParam(value = "sortOrder", defaultValue = DEFAULT_ORDER) String sortOrder,
            @RequestParam(value = "pageSize", defaultValue = DEFAULT_PAGE_SIZE) int pageSize,
            @RequestParam(value = "pageNumber", defaultValue = DEFAULT_PAGE_NUMBER) int pageNumber) {
        final QueryControl queryControl = new QueryControl(sortBy, sortOrder, pageSize, pageNumber);

        final IntervalItem interval = searchService.searchTopicIntervalAssocByTopicIdAndIntervalid(topicId, intervalId);

        PaginatedSearchResult<TweetItem> relatedTweets = null;
        PaginatedSearchResult<UserItem> relatedUsers = null;
        PaginatedSearchResult<HashTagItem> relatedTags = null;

        if (ENTITY_USER.equalsIgnoreCase(entityType)) {
            if (ENTITY_TWEET.equalsIgnoreCase(relatedEntityType)) {
                relatedTweets = searchService.searchUserBasedTweetRankings(entityId, topicId, intervalId, queryControl);
            } else if (ENTITY_TAG.equalsIgnoreCase(relatedEntityType)) {
                relatedTags = searchService.searchUserBasedTagRankings(entityId, topicId, intervalId, queryControl);
            } else {
                relatedTweets = searchService.searchUserBasedTweetRankings(entityId, topicId, intervalId, queryControl);
                relatedTags = searchService.searchUserBasedTagRankings(entityId, topicId, intervalId, queryControl);
            }
        } else if (ENTITY_TAG.equalsIgnoreCase(entityType)) {
            if (ENTITY_TWEET.equalsIgnoreCase(relatedEntityType)) {
                relatedTweets = searchService.searchTagBasedTweetRankings(entityId, topicId, intervalId, queryControl);
            } else if (ENTITY_USER.equalsIgnoreCase(relatedEntityType)) {
                relatedUsers = searchService.searchTagBasedUserRankings(entityId, topicId, intervalId, queryControl);
            } else {
                relatedTweets = searchService.searchTagBasedTweetRankings(entityId, topicId, intervalId, queryControl);
                relatedUsers = searchService.searchTagBasedUserRankings(entityId, topicId, intervalId, queryControl);
            }
        }

        return new AjaxRequestResult<SearchResultAggregate>(new SearchResultAggregate(interval, relatedTweets, relatedUsers, relatedTags));
    }
}
